//
//  OperationBlueTooth.m
//  Blue-toothLight
//
//  Created by mazg on 15/6/17.
//  Copyright (c) 2015年 mazg. All rights reserved.
//

#import "OperationBlueTooth.h"
#import "LightModel.h"
#import "NSManagedObject+helper.h"

static OperationBlueTooth *blueToothInstance=nil;

@implementation OperationBlueTooth
//返回当前类的单粒对象
+(instancetype)shareOperationBlueToothInsatnce{
    if (blueToothInstance==nil) {
        blueToothInstance=[[OperationBlueTooth alloc]init];
        
        [blueToothInstance scanForPeripherals];
        blueToothInstance.scanPerT=[NSTimer scheduledTimerWithTimeInterval:7.0 target:blueToothInstance selector:@selector(scanForPeripherals) userInfo:nil repeats:YES];
    }
    return blueToothInstance;
}

//搜索外围设备的方法
-(void)scanForPeripherals{
    //先清空数据
    [self.cbCentralMgr stopScan];
    
    
    //搜索
    NSDictionary * dic = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO],CBCentralManagerScanOptionAllowDuplicatesKey, nil];
    [self.cbCentralMgr scanForPeripheralsWithServices:nil options:dic];
}



#pragma mark 延迟实例化

-(CBCentralManager *)cbCentralMgr{
    if (!_cbCentralMgr) {
        _cbCentralMgr=[[CBCentralManager alloc]initWithDelegate:self queue:nil];
    }
    return _cbCentralMgr;
}

-(NSMutableArray *)perArr{
    if (!_perArr) {
        _perArr=[[NSMutableArray alloc]init];
    }
    return _perArr;
}

-(NSMutableArray *)perConnectedArr{
    if (!_perConnectedArr) {
        _perConnectedArr=[[NSMutableArray alloc]init];
    }
    return _perConnectedArr;
}

-(void)dealloc{
    blueToothInstance.scanPerT=nil;
    blueToothInstance.cbCentralMgr=nil;
    blueToothInstance=nil;
}

#pragma mark - tool
-(void)addLog:(NSString*)log
{
    NSLog(@"%@",log);
}

-(void)addLogWithService:(CBService*)service
{
    [self addLog:[NSString stringWithFormat:@"%@ uuid:%@",service,service.UUID]];
    
}
-(void)addLogWithCharacteristic:(CBCharacteristic*)characteristic
{
    [self addLog:[NSString stringWithFormat:@"%@ characteristic:%@",characteristic,characteristic.UUID]];
}



#pragma mark -CBCentralManagerDelegate
-(NSString*)getcentralManagerStateStr:(CBCentralManager*)central
{
    NSString* result;
    switch (central.state) {
        case CBCentralManagerStatePoweredOff:
            result = @"设备关闭";
            break;
            
        case CBCentralManagerStatePoweredOn:
            result = @"设备开启";
            break;
            
        case CBCentralManagerStateResetting:
            result = @"设备重置";
            break;
            
        case CBCentralManagerStateUnauthorized:
            result = @"未授权";
            break;
            
        case CBCentralManagerStateUnknown:
            result = @"未知";
            break;
            
        case CBCentralManagerStateUnsupported:
            result = @"不支持";
            break;
            
        default:
            result = @"没有啦";
            break;
    }
    return result;
}

//更新状态 ，只有状态可用的时候才能够进行创建服务，发布等等操作
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
    [self addLog:@"蓝牙设备状态开始更新"];
    switch (central.state) {
        case CBCentralManagerStateUnknown:
            [self addLog:@"未知"];
            break;
            
        case CBCentralManagerStateResetting:
            [self addLog:@"设备重置"];
            break;
            
        case CBCentralManagerStateUnsupported:
            [self addLog:@"不支持"];
            break;
            
        case CBCentralManagerStateUnauthorized:
            [self addLog:@"未授权"];
            break;
            
        case CBCentralManagerStatePoweredOff:
            [self addLog:@"设备关闭"];
            break;
            
        case CBCentralManagerStatePoweredOn:
            [self addLog:@"设备开启"];
            break;
            
        default:
            [self addLog:@"State 未知"];
            break;
    }
}

//这个方法是一旦扫描到外设就会调用的方法，注意此时并没有连接上外设，这个方法里面，你可以解析出当前扫描到的外设的广播包信息，当前RSSI等，现在很多的做法是，会根据广播包带出来的设备名，初步判断是不是自己公司的设备，才去连接这个设备，就是在这里面进行判断的
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
    NSLog(@"advertisementData = %@",advertisementData);
//    [self addLog:@"------------发现外围设备---------------"];
//    [self addLog:[peripheral.RSSI stringValue]];
//    [self addLog:[peripheral.identifier UUIDString]];
    NSLog(@"+++++++++++++++++++++++++++++++++++++++++++++++ 设备:%@",peripheral);
//    NSLog(@"＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋信号强度%@",RSSI);
    
    
//这里根据广播带出来的设备名字，排出掉其他没有用的蓝牙设备
    if (![advertisementData[@"kCBAdvDataLocalName"] isEqualToString:@"SimpleBLEPeripheral"]) {
        return;
    }
    
//这里如果数组中已经包含当前设备，就不需要反复添加到数组中了
    if ([self.perArr containsObject:peripheral]) {
        return;
    }
    
    [self.perArr addObject:peripheral];//将外围设备加入数组
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(reloadTableViewDataWithAllPer:andConnectedPer:)]) {
        [self.delegate reloadTableViewDataWithAllPer:self.perArr andConnectedPer:self.perConnectedArr];
    }
}



//已经连接到外围设备
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
    //1、添加到已连接到数组
    [self addLog:@"-------------didConnectPeripheral-----------------"];
    [self addLog:peripheral.name];
    [self.perConnectedArr addObject:peripheral];
    
    //2、修改数据库数据
    _dataBaseArr=[LightModel filter:nil orderby:nil offset:0 limit:0];
    for (LightModel *model in _dataBaseArr) {
        if ([model.perIdentifier isEqualToString:peripheral.identifier.UUIDString]) {
            model.isConnected=@YES;
        }
    }
    [LightModel save:^(NSError *error) {
        
    }];
    //3、通知代理人更新
    if (self.delegate && [self.delegate respondsToSelector:@selector(reloadTableViewDataWithAllPer:andConnectedPer:)]) {
        [self.delegate reloadTableViewDataWithAllPer:self.perArr andConnectedPer:self.perConnectedArr];
    }
    //4、指定设备代理并发现服务
    peripheral.delegate = self;//设置代理
    [peripheral discoverServices:nil];//连上外围设备，然后主动发现服务
}


//连接外围设备失败
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    [self addLog:@"-------------didFailToConnectPeripheral-----------------"];
    [self addLog:peripheral.name];
}


//已断开外围设备连接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    [self addLog:@"-------------didDisconnectPeripheral-----------------"];
    [self addLog:peripheral.name];
    [self.perConnectedArr removeObject:peripheral];
    
    //2、修改数据库数据
    _dataBaseArr=[LightModel filter:nil orderby:nil offset:0 limit:0];
    for (LightModel *model in _dataBaseArr) {
        if ([model.perIdentifier isEqualToString:peripheral.identifier.UUIDString]) {
            model.isConnected=@NO;
            model.isOpen=@NO;
        }
    }
    [LightModel save:^(NSError *error) {
        
    }];
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(reloadTableViewDataWithAllPer:andConnectedPer:)]) {
        [self.delegate reloadTableViewDataWithAllPer:self.perArr andConnectedPer:self.perConnectedArr];
    }
}






#pragma mark CBPeripheralDelegate



//到这里，说明你上面调用的  [m_peripheral discoverServices:nil]; 方法起效果了，我们接着来找找特征值UUID
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
    
    [self addLog:@"-------------didDiscoverServices-----------------"];
    [self addLog:peripheral.name];
    
    for (CBService* service in peripheral.services){
        [self addLogWithService:service];
        //查询服务所带的特征值
        [peripheral discoverCharacteristics:nil forService:service];
        //查询服务中的服务
        //        [peripheral discoverIncludedServices:nil forService:service];
    }
}


//发现了（指定）的特征值了，如果你想要有所动作，你可以直接在这里做，比如有些属性为 notify 的 Characteristics ,你想要监听他们的值，可以这样写 setNotifyValue:YES forCharacteristic
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
    [self addLog:@"-------------didDiscoverCharacteristicsForService-----------------"];
    [self addLog:peripheral.name];
    [self addLog:[NSString stringWithFormat:@"%@",service]];
    for (CBCharacteristic * characteristic in service.characteristics) {
        
        [self addLogWithCharacteristic:characteristic];
        //为特征添加通知
        [peripheral setNotifyValue:YES forCharacteristic:characteristic];
    }
}


//这个可是重点了，你收的一切数据，基本都从这里得到,你只要判断一下 [characteristic.UUID UUIDString] 符合你们定义的哪个，然后进行处理就行，值为：characteristic.value 一切数据都是这个，至于怎么解析，得看你们自己的了
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
//    [self addLog:@"-------------didUpdateValueForCharacteristic-----------------"];
//    [self addLog:peripheral.name];
//    [self addLog:[NSString stringWithFormat:@"%@ value:%@",characteristic,characteristic.value]];
    
    //1、打印颜色信息
    int a,b,c,d;
    NSData *data=characteristic.value;
    Byte *byte=(Byte *)[data bytes];
    a=byte[1];
    b=byte[2];
    c=byte[3];
    d=byte[4];
    
//    printf("颜色值：＋＋＋＋＋＋＋＋ a=%i,b=%i,c=%i,d=%i\n",a,b,c,d);
    
   //2、定时检测开关及颜色状态信息，保存数据
    _dataBaseArr=[LightModel filter:nil orderby:nil offset:0 limit:0];
    //是否需要刷新tableview，只有当检测到设备开关状态变化（由关到开或者由开到关），改变model值后才需要刷新tableview。
    //否则不需要刷新tableview。因为当前代理方法是每隔1秒调用一次，如果1秒刷新一次tableview，那tableview界面无法执行删除操作
    BOOL isNeedToReloadTableView=NO;
    for (LightModel *model in _dataBaseArr) {
        if ([model.perIdentifier isEqualToString:peripheral.identifier.UUIDString]) {
            if (a<5 && b<5 && c<5 && d<5) {
                if ([model.isOpen boolValue]) {
                    isNeedToReloadTableView=YES;
                    model.isOpen=@NO;
                    [LightModel save:^(NSError *error) {
                        
                    }];
                }
            }
            else{
                if (![model.isOpen boolValue]) {
                    isNeedToReloadTableView=YES;
                    model.isOpen=@YES;
                }
//                model.perColor=[UIColor colorWithRed:a/255.0f green:b/255.0f blue:c/25.0f alpha:d/255.0f];
                [LightModel save:^(NSError *error) {
                    
                }];
            }
        }
    }

    //3、通过代理更新界面
    if (isNeedToReloadTableView) {
        if (self.delegate && [self.delegate respondsToSelector:@selector(reloadTableViewDataWithAllPer:andConnectedPer:)]) {
            [self.delegate reloadTableViewDataWithAllPer:self.perArr andConnectedPer:self.perConnectedArr];
        }
    }
}


//这个方法比较好，这个是你发数据到外设的某一个特征值上面，并且响应的类型是 CBCharacteristicWriteWithResponse ，上面的官方文档也有，如果确定发送到外设了，就会给你一个回应，当然，这个也是要看外设那边的特征值UUID的属性是怎么设置的,看官方文档，人家已经说了，条件是，特征值UUID的属性：CBCharacteristicWriteWithResponse
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
//    [self addLog:@"-------------didWriteValueForCharacteristic-----------------"];
//    [self addLog:peripheral.name];
//    if ([[[UIDevice currentDevice] systemVersion] floatValue]>=7.0)
//    {
//        [self addLog:[NSString stringWithFormat:@"%@ value:%@",characteristic,characteristic.value]];//ios7时，这里的value并不是写进去的值
//    }else{
//        [self addLog:[NSString stringWithFormat:@"%@ value:%@",characteristic,characteristic.value]];
//    }
}

//这个方法被调用是因为你主动调用方法： setNotifyValue:forCharacteristic 给你的反馈
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
    [self addLog:@"-------------didUpdateNotificationStateForCharacteristic-----------------"];
    [self addLog:peripheral.name];
    [self addLog:[NSString stringWithFormat:@"%@",characteristic]];
}


#pragma mark 蓝牙 不用
/*
 //根据蓝牙设备的信息同步app状态
 - (void)centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary *)dict
 {
 [self addLog:@"-------------重置状态willRestoreState-----------------"];
 [self addLog:[NSString stringWithFormat:@"%@",dict]];
 }
 
 
 
 //得到可以回复设备的Array
 - (void)centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals
 {
 [self addLog:@"-------------didRetrievePeripherals-----------------"];
 for (CBPeripheral * peripheral in peripherals) {
 [self addLog:[NSString stringWithFormat:@"%@ name:%@",peripheral,peripheral.name]];
 }
 
 }
 
 //得到已经连上的可以回复的设备Array，这个方法当connectPeripheral:options 连接成功后被唤醒
 - (void)centralManager:(CBCentralManager *)central didRetrieveConnectedPeripherals:(NSArray *)peripherals
 {
 [self addLog:@"-------------didRetrieveConnectedPeripherals-----------------"];
 for (CBPeripheral * peripheral in peripherals) {
 [self addLog:[NSString stringWithFormat:@"%@ name:%@",peripheral,peripheral.name]];
 }
 }

 
 
 
 //发现特征的描述
 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
 {
 [self addLog:@"-------------didDiscoverDescriptorsForCharacteristic-----------------"];
 [self addLog:peripheral.name];
 [self addLog:[NSString stringWithFormat:@"%@",characteristic]];
 
 }
 
 
 //更新描述信息
 - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error
 {
 [self addLog:@"-------------didUpdateValueForDescriptor-----------------"];
 [self addLog:peripheral.name];
 [self addLog:[NSString stringWithFormat:@"%@",descriptor]];
 }
 
 
 //已经写入描述信息
 - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error
 {
 [self addLog:@"-------------didWriteValueForDescriptor-----------------"];
 [self addLog:peripheral.name];
 [self addLog:[NSString stringWithFormat:@"%@",descriptor]];
 }
 
 
 
 //这个函数一般不会被调用，他被调用是因为 peripheral.name 被修改了，才会被调用
 - (void)peripheralDidUpdateName:(CBPeripheral *)peripheral NS_AVAILABLE(NA, 6_0)
 {
 [self addLog:@"-------------peripheralDidUpdateName-----------------"];
 [self addLog:peripheral.name];
 }
 
 
 //这个函数一般也不会被调用，它是在你已经读取过一次外设的 services 之后，没有断开，这个时候外设突然来个我的某个服务不让用了，这个时候才会被调用，你得要再一次读取外设的 services 即可
 - (void)peripheralDidInvalidateServices:(CBPeripheral *)peripheral NS_DEPRECATED(NA, NA, 6_0, 7_0)
 {
 [self addLog:@"-------------peripheralDidInvalidateServices-----------------"];
 [self addLog:peripheral.name];
 
 }
 
 
 //这个函数一般也不会被调用，它是在你已经读取过一次外设的 services 之后，没有断开，这个时候外设突然来个我的某个服务不让用了，这个时候才会被调用，你得要再一次读取外设的 services 即可
 - (void)peripheral:(CBPeripheral *)peripheral didModifyServices:(NSArray *)invalidatedServices NS_AVAILABLE(NA, 7_0)
 {
 [self addLog:@"-------------didModifyServices-----------------"];
 [self addLog:peripheral.name];
 }
 
 
 //发现服务中的服务
 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverIncludedServicesForService:(CBService *)service error:(NSError *)error
 {
 [self addLog:@"-------------didDiscoverIncludedServicesForService-----------------"];
 [self addLog:peripheral.name];
 [self addLogWithService: service];
 for (CBService * server in service.includedServices) {
 [self addLogWithService: server];
 }
 }
 
 
 //这个函数一看就知道了，当外设更新了RSSI的时候被调用，当然，外设不会无故给你老是发RSSI，听硬件那边工程师说，蓝牙协议栈里面的心跳包是可以把RSSI带过来的，但是不知道什么情况，被封杀了，你的要主动调用 [peripheral readRSSI];方法，人家外设才给你回RSSI，不过这个方法现在被弃用了。用下面的方法来接收
 //已经弃用
 - (void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError *)error
 {
 [self addLog:@"-------------peripheralDidUpdateRSSI-----------------"];
 [self addLog:peripheral.name];
 }
 
 
 //同上，这个就是你主动调用了 [peripheral readRSSI];方法回调的RSSI，你可以根据这个RSSI估算一下距离什么的
 - (void)peripheral:(CBPeripheral *)peripheral didReadRSSI:(NSNumber *)RSSI error:(NSError *)error NS_AVAILABLE(NA, 8_0);
 {
 NSLog(@" peripheral Current RSSI:%@",RSSI);
 }
 
 */




@end
